package pro2_transport;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.oio.OioServerSocketChannel;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

/**
 * @program: netty
 * @description: 使用netty实现阻塞式tcp通信
 * @author: zy
 * @create: 2025-03-12 10:06
 */
public class P3_NettyOioServer {
    public static void main(String[] args) throws Exception {
        new P3_NettyOioServer().server(9999);
    }
    public void server(int port) throws Exception {
        // 准备要发送的数据
        // ByteBuf 是 Netty 的缓冲区对象，支持引用计数（自动内存管理）
        // Unpooled.unreleasableBuffer：返回一个不可释放的缓冲区（引用计数不会减到 0）
        // 这里写入了一段 UTF-8 编码的字符串
        final ByteBuf buf = Unpooled.unreleasableBuffer(
                Unpooled.copiedBuffer("Hi, 我是 基于 netty的NIO通信!\r\n", Charset.forName("gbk"))
        );
        // 创建一个 EventLoopGroup，负责管理所有事件循环
        // OioEventLoopGroup 表示 **阻塞 I/O**（Old IO），每个连接使用一个线程
        EventLoopGroup group = new OioEventLoopGroup();    // ************** 关键点: 阻塞式IO **************
        try {
            // 创建并配置服务器启动辅助类
            ServerBootstrap b = new ServerBootstrap();
            b.group(group) // 设置 EventLoopGroup，处理所有事件
                    .channel(OioServerSocketChannel.class) // ************** 关键点: 使用阻塞式的 ServerSocketChannel **************
                    .localAddress(new InetSocketAddress(port)) // 绑定服务端端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 配置子通道的处理器（每个新连接都会调用）
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            // 获取当前通道的 pipeline（责任链模式，用于处理入站/出站事件）
                            ch.pipeline().addLast(
                                    // 添加一个入站事件处理器（自定义）   与前面的区别在于，这是一个匿名内部类的写法
                                    new ChannelInboundHandlerAdapter() {
                                        @Override
                                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                            // 当客户端连接成功并激活时，执行此方法
                                            // 将准备好的数据写入客户端，并刷新到网络
                                            ctx.writeAndFlush(buf.duplicate())
                                                    // 添加一个监听器，当写操作完成并关闭通道时，释放资源
                                                    .addListener(ChannelFutureListener.CLOSE);
                                        }
                                    });
                        }
                    });
            // 绑定服务器端口，并阻塞等待绑定完成
            ChannelFuture f = b.bind().sync();
            // 阻塞等待，直到服务器通道关闭
            f.channel().closeFuture().sync();
        } finally {
            // 优雅关闭 EventLoopGroup，释放所有资源
            group.shutdownGracefully().sync();
        }
    }
}
